Load libraries
library(tidytext)
library(tidyverse)
library(quanteda)
library(lubridate)
library(ggplot2)
library(plotly)
library(forcats)
library(readxl)
library(leaflet)
library(leaflet.minicharts)
library(sp)
library(sf)
library(readr)
library(stringr)
library(rtweet)
library(ggraph)
library(ggrepel)
library(tidygraph)
Load Data
Parlamentarier <- read_csv("Data/Parlamentarier.csv")
EU-Parlament rausfiltern
Parlamentarier <- Parlamentarier %>%
filter(Kategorie!="EU-Parlament")
Read Tabellen mit fehlenden Geschlechtern
alle_geschlechter <- read_excel("Data/Parlamentarier_geschechter.xlsx", sheet = "Geschlechter")
Join fehlende Geschlechterangaben
Parlamentarier <- Parlamentarier %>%
left_join(alle_geschlechter, by = c("Name" = "Name"))
Rename Spalten
Parlamentarier <- Parlamentarier %>%
rename(Geschlecht = Geschlecht.y)
Bundestag Geschlechterverteilung pro Partei
- filtern nach Bundestag
- CDU & CSU zusammenfügen
- nach männlich und weiblich gruppieren, Anzahl berechnen und sortieren
bundestag <- Parlamentarier %>%
select(id, Name, Geschlecht, Partei, Kategorie, SM_Twitter_id, SM_Twitter_user) %>%
filter(Kategorie=="Bundestag")
bundestag$Partei[bundestag$Partei == "CSU"] <-"CDU/CSU"
bundestag$Partei[bundestag$Partei=="CDU"]<-"CDU/CSU"
bundestag_man <- bundestag %>%
group_by(Partei) %>%
filter(Geschlecht == "männlich") %>%
summarise(gesamt_man=n())
bundestag_gesamt <- bundestag %>%
group_by(Partei) %>%
filter(Geschlecht == "weiblich") %>%
summarise(gesamt_frau=n()) %>%
left_join(bundestag_man) %>%
mutate(row_sum=rowSums(.[2:3])) %>%
arrange(desc(row_sum))
Barchart Bundestag
- Stacked-Barchart zur Geschlechterverteilung im Bundestag pro Partei
- visualisierung der Daten in möglichst geschlechterneuralen Farben
plot_ly(data=bundestag_gesamt, x=~reorder(Partei,-row_sum), y=~gesamt_frau, name="weiblich", marker=list(color=toRGB("#FB7F62")),
type="bar", hoverinfo="text", text=~paste("",row_sum),
hovertemplate=paste("Anzahl: %{y:,.0f}",
"<br>Gesamtanzahl: %{text}")) %>%
add_trace(y=~gesamt_man, name="männlich", marker=list(color=toRGB("#775285"))) %>%
layout(barmode="stack", title="Geschlechterverteilung in den Parteien im Bundestag", # titel position und größe ändern
xaxis = list(title = ""), yaxis=list(title="Anzahl Abgeordnete")) %>%
layout(legend=list(x=1, y=0.5))
Landtag Geschlechterverteilung pro Partei
- filtern allen Landtagen
- CDU & CSU sowie FDP & DVP zusammenfügen
- nach männlich und weiblich gruppieren, Anzahl berechnen und sortieren
landtag_partei <- Parlamentarier %>%
filter(Kategorie !="Bundestag") %>%
filter(Kategorie!="EU-Parlament") %>%
filter(Partei !="BIW") %>%
filter(Partei!="SSW") %>%
filter(Partei!="BVB/FW") %>%
filter(Partei!="FW")
landtag_partei$Partei[landtag_partei$Partei == "CSU"] <-"CDU/CSU"
landtag_partei$Partei[landtag_partei$Partei=="CDU"] <- "CDU/CSU"
landtag_partei$Partei[landtag_partei$Partei=="FDP/DVP"] <- "FDP"
landtag_man <- landtag_partei %>%
group_by(Partei) %>%
filter(Geschlecht=="männlich") %>%
summarise(gesamt_man=n())
landtag_gesamt <- landtag_partei %>%
group_by(Partei) %>%
filter(Geschlecht=="weiblich") %>%
summarise(gesamt_frau=n()) %>%
left_join(landtag_man) %>%
mutate(row_sum=rowSums(.[2:3])) %>%
arrange(desc(row_sum))
Joining, by = "Partei"
Barchart Landtag
- Stacked-Barchart zur Geschlechterverteilung in den Landtagen pro Partei
- visualisierung der Daten in möglichst geschlechterneuralen Farben
plot_ly(data=landtag_gesamt, x=~reorder(Partei,-row_sum), y=~gesamt_frau, name="weiblich", marker=list(color=toRGB("#FB7F62")),
type="bar", hoverinfo="text", text=~paste("",row_sum),
hovertemplate=paste("Anzahl: %{y:,.0f}",
"<br>Gesamtanzahl: %{text}")) %>%
add_trace(y=~gesamt_man, name="männlich", marker=list(color=toRGB("#775285"))) %>%
layout(barmode="stack", title="Geschlechterverteilung in den Parteien in den Landtagen", # titel position und größe ändern
xaxis=list(title=""), yaxis=list(title="Anzahl Abgeordnete")) %>%
layout(legend=list(x=1, y=0.5))
Map mit Geschlechterverteilung in den Landtagen
- Alle Landtage herausfiltern
parlamentarier_landtag <- Parlamentarier %>%
filter(Kategorie %in% c("Abgeordnetenhaus von Berlin",
"Bayerischer Landtag",
"Bremische Bürgerschaft",
"Hamburgische Bürgerschaft",
"Hessischer Landtag",
"Landtag Brandenburg",
"Landtag des Saarlandes",
"Landtag Mecklenburg-Vorpommern",
"Landtag Nordrhein-Westfalen",
"Landtag Rheinland-Pfalz",
"Landtag Sachsen-Anhalt",
"Landtag von Baden-Württemberg",
"Niedersächsischer Landtag",
"Sächsischer Landtag",
"Schleswig-Holsteinischer Landtag",
"Thüringer Landtag"))
- Vektoren und Dataframe erstellen mit den Koordinaten an denen die späteren Pie-Charts fixiert werden sollen. (Immer genau im Mittelpunkt des Bundeslandes)
Kategorie <- c("Abgeordnetenhaus von Berlin",
"Bayerischer Landtag",
"Bremische Bürgerschaft",
"Hamburgische Bürgerschaft",
"Hessischer Landtag",
"Landtag Brandenburg",
"Landtag des Saarlandes",
"Landtag Mecklenburg-Vorpommern",
"Landtag Nordrhein-Westfalen",
"Landtag Rheinland-Pfalz",
"Landtag Sachsen-Anhalt",
"Landtag von Baden-Württemberg",
"Niedersächsischer Landtag",
"Sächsischer Landtag",
"Schleswig-Holsteinischer Landtag",
"Thüringer Landtag")
lat <- c(52.520008,
48.917431,
53.074982,
53.553815,
50.652052,
52.408418,
49.396423,
53.612651,
51.433237,
50.118346,
51.950265,
48.661604,
52.636704,
51.104541,
54.219367,
51.010989)
lng <- c(13.404954,
11.407980,
8.807080,
9.991575,
9.162438,
12.562492,
7.022961,
12.429595,
7.661594,
7.308953,
11.692274,
9.350134,
9.845077,
13.201738,
9.696117,
10.845346)
bundeslaender_koordinaten <- data.frame(Kategorie, lat, lng)
- Dataframe nach Anzahl der männlichen und weiblichen Politiker*innen pro Bundesland filtern.
parlamentarier_man <- parlamentarier_landtag %>%
group_by(Kategorie) %>%
filter(Geschlecht == "männlich") %>%
summarise(männlich = n())
parlamentarier_landtag_gesamt <- parlamentarier_landtag %>%
group_by(Kategorie) %>%
filter(Geschlecht == "weiblich") %>%
summarise(weiblich = n()) %>%
left_join(parlamentarier_man)
Joining, by = "Kategorie"
- Koordinaten der späteren Pie-Charts zur Haupttabelle joinen
parlamentarier_koordinaten <- parlamentarier_landtag_gesamt %>%
left_join(bundeslaender_koordinaten, by = c("Kategorie" = "Kategorie"))
Map mit Pie-Charts
- geschlechterneutrale Farben für die Geschlechterverteilung erstellen, sowie die Grenzen der Bundesländer importieren und mit Namen versehen (popup).
colors <- c("#FB7F62", "#775285")
grenzen <- readRDS("Data/gadm36_DEU_1_sp.rds") %>%
st_as_sf()
popup_bundeslaender <- paste0("<strong>Bundesland: </strong>", grenzen$NAME_1)
- Pie-Charts mit Hilfe von addMinicharts zur Karte angefügt.
map <- leaflet() %>%
addProviderTiles(providers$CartoDB.VoyagerLabelsUnder) %>%
setView(lng = 10.451526, lat = 51.165691, zoom = 5.5) %>%
addPolygons(data = grenzen,
fillColor = "grey",
fillOpacity = 0.1,
weight = 3,
color = "grey",
popup = popup_bundeslaender) %>%
addMinicharts(
parlamentarier_koordinaten$lng, parlamentarier_koordinaten$lat,
type = "pie",
chartdata = parlamentarier_koordinaten[, c("weiblich", "männlich")],
colorPalette = colors,
width = 46,
height = 46,
opacity = 0.8,
legendPosition = "bottomright"
)
sf layer has inconsistent datum (+proj=longlat +ellps=WGS84 +towgs84=0,0,0,0,0,0,0 +no_defs).
Need '+proj=longlat +datum=WGS84'
map
Sentimentanalyse
- nach den “großen” Parteien filtern
- alle Politiker*innen entfernen, welche keinen Twitteraccount besitzen
- Usernames in Kleinschreibung formatieren
Parlamentarier_senti <- Parlamentarier %>%
filter(Partei!="BIW") %>%
filter(Partei!="SSW") %>%
filter(Partei!="BVB/FW") %>%
filter(Partei!="FW") %>%
filter(Partei!="fraktionslos") %>%
filter(SM_Twitter_user != "") %>%
select(Name, Partei, SM_Twitter_user, Geschlecht) %>%
mutate(SM_Twitter_user=tolower(SM_Twitter_user))
- CDU & CSU sowie FDP & DVP zusammenfügen
Parlamentarier_senti$Partei[Parlamentarier_senti$Partei == "CSU"] <- "CDU/CSU"
Parlamentarier_senti$Partei[Parlamentarier_senti$Partei == "CDU"] <- "CDU/CSU"
Parlamentarier_senti$Partei[Parlamentarier_senti$Partei == "FDP/DVP"] <- "FDP"
load("Data/sentiWS.RData")
sentiws <- dictionary(list(positive=positive, negative=negative))
- Corpus aus den Texten der gefilterten Tweets bilden
tweet_corpus <- corpus(filtert_tweets, text_field = "text")
- tokenisieren der Texte und bilden einer DFM
- sentiws und “Tweet-Tokens” zusammenführen, sowie nach screen_name gruppieren
token <- tokens(tweet_corpus)
dfm <- dfm(token)
senti <- dfm_lookup(dfm, sentiws)
senti <- dfm_group(senti, groups = screen_name)
- DFM zum Dataframe konvertieren
- doc_id in Kleinschreibung formatieren
- Parlamentarier_senti joinen
- Gruppieren nach Partei
- Sentiment der einzelnen User*innen auf Parteiebene zusammenfassen und Verhältnis positive/negative bilden
senti_frame <- senti %>%
convert(to= "data.frame") %>%
as_tibble() %>%
mutate(doc_id=tolower(doc_id))
Fehler in UseMethod("convert") :
nicht anwendbare Methode für 'convert' auf Objekt der Klasse "c('dfm', 'dgCMatrix', 'CsparseMatrix', 'dsparseMatrix', 'generalMatrix', 'dCsparseMatrix', 'dMatrix', 'sparseMatrix', 'compMatrix', 'Matrix', 'xMatrix', 'mMatrix', 'Mnumeric', 'replValueSp')" angewendet
Barchart
- Partei absteigend nach negativem Sentiment sortieren
- Beschriftung der X- und Y Werte ändern
- Barchart bilden und in ggplotly konvertieren
senti_bar <- senti_final_frame %>%
mutate(Partei = fct_reorder(Partei, positive, max)) %>%
pivot_longer(c(positive, negative), values_to = c("Verhältnis"), names_to = c("Äußerung")) %>%
ggplot() +
geom_bar(aes(Partei,
Verhältnis,
fill = Äußerung),
position = "stack",
stat = "identity") +
scale_fill_manual(values = c("#f46666", "#8EC9BB")) +
theme_classic() +
labs(
title = "Äußerungen der Politiker*innen auf Twitter zum Thema 'Gender'",
subtitle = "Einschätzung durch Sentimentanalyse",
x = "Partei",
y = "Verhältnis",
fill = "Äußerung"
)
Fehler in mutate(., Partei = fct_reorder(Partei, positive, max)) :
Objekt 'senti_final_frame' nicht gefunden
Netzwerk
Zuweisung von Attributen an Nodes: * Parteizugehörigkeit in Farbe * Klarname der Politikerinnen als Label Anzahl der Tweets in Größe
netz_plot <- netz %>%
filter(component <= 6) %>%
mutate(degree = centrality_degree(mode = "in")) %>%
ggraph(layout = "fr") +
geom_edge_link(alpha = 0.25, arrow = arrow(length = unit("5", "mm"))) +
geom_node_point(aes(size = n, color = Partei)) +
scale_color_manual(values = partei_farben) +
theme_graph(background = "white") + # theme
geom_node_label(aes(filter = n >= 15, label = Name), repel = T, show.legend = F, alpha = 0.5) + #position = "jitter"
labs(title = "Retweet-Netzwerke deutscher Politiker*innen", size = "Anzahl Tweets", subtitle = "zum Thema 'Gender' ab 2016")
netz_plot

NODES DEUTLICHERE ABSTUFUNG, VLT. THEME FUNKTIONIERT NICHT RICHTIG
LS0tDQp0aXRsZTogIlJfUHJvamVrdF9HZW5kZXIiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sgDQotLS0NCiMgTG9hZCBsaWJyYXJpZXMgDQoNCmBgYHtyfQ0KbGlicmFyeSh0aWR5dGV4dCkgDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkocXVhbnRlZGEpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkocGxvdGx5KQ0KbGlicmFyeShmb3JjYXRzKQ0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KGxlYWZsZXQpDQpsaWJyYXJ5KGxlYWZsZXQubWluaWNoYXJ0cykNCmxpYnJhcnkoc3ApDQpsaWJyYXJ5KHNmKQ0KbGlicmFyeShyZWFkcikNCmxpYnJhcnkoc3RyaW5ncikNCmxpYnJhcnkocnR3ZWV0KQ0KbGlicmFyeShnZ3JhcGgpDQpsaWJyYXJ5KGdncmVwZWwpDQpsaWJyYXJ5KHRpZHlncmFwaCkNCmBgYA0KDQojIExvYWQgRGF0YSANCg0KYGBge3J9DQpQYXJsYW1lbnRhcmllciA8LSByZWFkX2NzdigiRGF0YS9QYXJsYW1lbnRhcmllci5jc3YiKQ0KYGBgDQoNCkVVLVBhcmxhbWVudCByYXVzZmlsdGVybg0KYGBge3J9DQpQYXJsYW1lbnRhcmllciA8LSBQYXJsYW1lbnRhcmllciAlPiUgDQogIGZpbHRlcihLYXRlZ29yaWUhPSJFVS1QYXJsYW1lbnQiKQ0KYGBgDQoNClJlYWQgVGFiZWxsZW4gbWl0IGZlaGxlbmRlbiBHZXNjaGxlY2h0ZXJuDQpgYGB7cn0NCmFsbGVfZ2VzY2hsZWNodGVyIDwtIHJlYWRfZXhjZWwoIkRhdGEvUGFybGFtZW50YXJpZXJfZ2VzY2hlY2h0ZXIueGxzeCIsIHNoZWV0ID0gIkdlc2NobGVjaHRlciIpDQpgYGANCg0KSm9pbiBmZWhsZW5kZSBHZXNjaGxlY2h0ZXJhbmdhYmVuIA0KYGBge3J9DQpQYXJsYW1lbnRhcmllciA8LSBQYXJsYW1lbnRhcmllciAlPiUgDQogIGxlZnRfam9pbihhbGxlX2dlc2NobGVjaHRlciwgYnkgPSBjKCJOYW1lIiA9ICJOYW1lIikpDQpgYGANCg0KUmVuYW1lIFNwYWx0ZW4NCmBgYHtyfQ0KUGFybGFtZW50YXJpZXIgPC0gUGFybGFtZW50YXJpZXIgJT4lIA0KICByZW5hbWUoR2VzY2hsZWNodCA9IEdlc2NobGVjaHQueSkNCmBgYA0KDQojIEJ1bmRlc3RhZyBHZXNjaGxlY2h0ZXJ2ZXJ0ZWlsdW5nIHBybyBQYXJ0ZWkNCg0KKiBmaWx0ZXJuIG5hY2ggQnVuZGVzdGFnDQoqIENEVSAmIENTVSB6dXNhbW1lbmbDvGdlbiANCiogbmFjaCBtw6RubmxpY2ggdW5kIHdlaWJsaWNoIGdydXBwaWVyZW4sIEFuemFobCBiZXJlY2huZW4gdW5kIHNvcnRpZXJlbg0KYGBge3J9DQpidW5kZXN0YWcgPC0gUGFybGFtZW50YXJpZXIgJT4lIA0KICBzZWxlY3QoaWQsIE5hbWUsIEdlc2NobGVjaHQsIFBhcnRlaSwgS2F0ZWdvcmllLCBTTV9Ud2l0dGVyX2lkLCBTTV9Ud2l0dGVyX3VzZXIpICU+JSANCiAgZmlsdGVyKEthdGVnb3JpZT09IkJ1bmRlc3RhZyIpDQoNCmJ1bmRlc3RhZyRQYXJ0ZWlbYnVuZGVzdGFnJFBhcnRlaSA9PSAiQ1NVIl0gPC0iQ0RVL0NTVSINCmJ1bmRlc3RhZyRQYXJ0ZWlbYnVuZGVzdGFnJFBhcnRlaT09IkNEVSJdPC0iQ0RVL0NTVSINCg0KYnVuZGVzdGFnX21hbiA8LSBidW5kZXN0YWcgJT4lIA0KICBncm91cF9ieShQYXJ0ZWkpICU+JSANCiAgZmlsdGVyKEdlc2NobGVjaHQgPT0gIm3DpG5ubGljaCIpICU+JSANCiAgc3VtbWFyaXNlKGdlc2FtdF9tYW49bigpKQ0KDQpidW5kZXN0YWdfZ2VzYW10IDwtIGJ1bmRlc3RhZyAlPiUgDQogIGdyb3VwX2J5KFBhcnRlaSkgJT4lIA0KICBmaWx0ZXIoR2VzY2hsZWNodCA9PSAid2VpYmxpY2giKSAlPiUgDQogIHN1bW1hcmlzZShnZXNhbXRfZnJhdT1uKCkpICU+JSANCiAgbGVmdF9qb2luKGJ1bmRlc3RhZ19tYW4pICU+JSANCiAgbXV0YXRlKHJvd19zdW09cm93U3VtcyguWzI6M10pKSAlPiUgDQogIGFycmFuZ2UoZGVzYyhyb3dfc3VtKSkNCmBgYA0KDQojIyMgQmFyY2hhcnQgQnVuZGVzdGFnDQoNCiogU3RhY2tlZC1CYXJjaGFydCB6dXIgR2VzY2hsZWNodGVydmVydGVpbHVuZyBpbSBCdW5kZXN0YWcgcHJvIFBhcnRlaQ0KKiB2aXN1YWxpc2llcnVuZyBkZXIgRGF0ZW4gaW4gbcO2Z2xpY2hzdCBnZXNjaGxlY2h0ZXJuZXVyYWxlbiBGYXJiZW4NCmBgYHtyfQ0KcGxvdF9seShkYXRhPWJ1bmRlc3RhZ19nZXNhbXQsIHg9fnJlb3JkZXIoUGFydGVpLC1yb3dfc3VtKSwgeT1+Z2VzYW10X2ZyYXUsIG5hbWU9IndlaWJsaWNoIiwgbWFya2VyPWxpc3QoY29sb3I9dG9SR0IoIiNGQjdGNjIiKSksDQogICAgICAgIHR5cGU9ImJhciIsIGhvdmVyaW5mbz0idGV4dCIsIHRleHQ9fnBhc3RlKCIiLHJvd19zdW0pLCANCiAgICAgICAgaG92ZXJ0ZW1wbGF0ZT1wYXN0ZSgiQW56YWhsOiAle3k6LC4wZn0iLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiPGJyPkdlc2FtdGFuemFobDogJXt0ZXh0fSIpKSAlPiUgDQogIGFkZF90cmFjZSh5PX5nZXNhbXRfbWFuLCBuYW1lPSJtw6RubmxpY2giLCBtYXJrZXI9bGlzdChjb2xvcj10b1JHQigiIzc3NTI4NSIpKSkgJT4lIA0KICBsYXlvdXQoYmFybW9kZT0ic3RhY2siLCB0aXRsZT0iR2VzY2hsZWNodGVydmVydGVpbHVuZyBpbiBkZW4gUGFydGVpZW4gaW0gQnVuZGVzdGFnIiwgIyB0aXRlbCBwb3NpdGlvbiB1bmQgZ3LDtsOfZSDDpG5kZXJuDQogICAgICAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAiIiksIHlheGlzPWxpc3QodGl0bGU9IkFuemFobCBBYmdlb3JkbmV0ZSIpKSAlPiUNCiAgbGF5b3V0KGxlZ2VuZD1saXN0KHg9MSwgeT0wLjUpKQ0KYGBgDQoNCiMgTGFuZHRhZyBHZXNjaGxlY2h0ZXJ2ZXJ0ZWlsdW5nIHBybyBQYXJ0ZWkNCg0KKiBmaWx0ZXJuIGFsbGVuIExhbmR0YWdlbg0KKiBDRFUgJiBDU1Ugc293aWUgRkRQICYgRFZQIHp1c2FtbWVuZsO8Z2VuIA0KKiBuYWNoIG3DpG5ubGljaCB1bmQgd2VpYmxpY2ggZ3J1cHBpZXJlbiwgQW56YWhsIGJlcmVjaG5lbiB1bmQgc29ydGllcmVuDQpgYGB7cn0NCmxhbmR0YWdfcGFydGVpIDwtIFBhcmxhbWVudGFyaWVyICU+JSANCiAgZmlsdGVyKEthdGVnb3JpZSAhPSJCdW5kZXN0YWciKSAlPiUgDQogIGZpbHRlcihLYXRlZ29yaWUhPSJFVS1QYXJsYW1lbnQiKSAlPiUgDQogIGZpbHRlcihQYXJ0ZWkgIT0iQklXIikgJT4lIA0KICBmaWx0ZXIoUGFydGVpIT0iU1NXIikgJT4lIA0KICBmaWx0ZXIoUGFydGVpIT0iQlZCL0ZXIikgJT4lIA0KICBmaWx0ZXIoUGFydGVpIT0iRlciKQ0KYGBgDQoNCmBgYHtyfQ0KbGFuZHRhZ19wYXJ0ZWkkUGFydGVpW2xhbmR0YWdfcGFydGVpJFBhcnRlaSA9PSAiQ1NVIl0gPC0iQ0RVL0NTVSINCmxhbmR0YWdfcGFydGVpJFBhcnRlaVtsYW5kdGFnX3BhcnRlaSRQYXJ0ZWk9PSJDRFUiXSA8LSAiQ0RVL0NTVSINCmxhbmR0YWdfcGFydGVpJFBhcnRlaVtsYW5kdGFnX3BhcnRlaSRQYXJ0ZWk9PSJGRFAvRFZQIl0gPC0gIkZEUCIgDQpgYGANCg0KYGBge3J9DQpsYW5kdGFnX21hbiA8LSBsYW5kdGFnX3BhcnRlaSAlPiUgDQogIGdyb3VwX2J5KFBhcnRlaSkgJT4lIA0KICBmaWx0ZXIoR2VzY2hsZWNodD09Im3DpG5ubGljaCIpICU+JSANCiAgc3VtbWFyaXNlKGdlc2FtdF9tYW49bigpKQ0KDQpsYW5kdGFnX2dlc2FtdCA8LSBsYW5kdGFnX3BhcnRlaSAlPiUgDQogIGdyb3VwX2J5KFBhcnRlaSkgJT4lIA0KICBmaWx0ZXIoR2VzY2hsZWNodD09IndlaWJsaWNoIikgJT4lIA0KICBzdW1tYXJpc2UoZ2VzYW10X2ZyYXU9bigpKSAlPiUgDQogIGxlZnRfam9pbihsYW5kdGFnX21hbikgJT4lIA0KICAgbXV0YXRlKHJvd19zdW09cm93U3VtcyguWzI6M10pKSAlPiUgDQogIGFycmFuZ2UoZGVzYyhyb3dfc3VtKSkNCmBgYA0KDQojIyMgQmFyY2hhcnQgTGFuZHRhZw0KDQoqIFN0YWNrZWQtQmFyY2hhcnQgenVyIEdlc2NobGVjaHRlcnZlcnRlaWx1bmcgaW4gZGVuIExhbmR0YWdlbiBwcm8gUGFydGVpDQoqIHZpc3VhbGlzaWVydW5nIGRlciBEYXRlbiBpbiBtw7ZnbGljaHN0IGdlc2NobGVjaHRlcm5ldXJhbGVuIEZhcmJlbg0KYGBge3J9DQpwbG90X2x5KGRhdGE9bGFuZHRhZ19nZXNhbXQsIHg9fnJlb3JkZXIoUGFydGVpLC1yb3dfc3VtKSwgeT1+Z2VzYW10X2ZyYXUsIG5hbWU9IndlaWJsaWNoIiwgbWFya2VyPWxpc3QoY29sb3I9dG9SR0IoIiNGQjdGNjIiKSksIA0KICAgICAgICB0eXBlPSJiYXIiLCBob3ZlcmluZm89InRleHQiLCB0ZXh0PX5wYXN0ZSgiIixyb3dfc3VtKSwgDQogICAgICAgIGhvdmVydGVtcGxhdGU9cGFzdGUoIkFuemFobDogJXt5OiwuMGZ9IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIjxicj5HZXNhbXRhbnphaGw6ICV7dGV4dH0iKSkgJT4lIA0KICBhZGRfdHJhY2UoeT1+Z2VzYW10X21hbiwgbmFtZT0ibcOkbm5saWNoIiwgbWFya2VyPWxpc3QoY29sb3I9dG9SR0IoIiM3NzUyODUiKSkpICU+JSANCiAgbGF5b3V0KGJhcm1vZGU9InN0YWNrIiwgdGl0bGU9Ikdlc2NobGVjaHRlcnZlcnRlaWx1bmcgaW4gZGVuIFBhcnRlaWVuIGluIGRlbiBMYW5kdGFnZW4iLCAjIHRpdGVsIHBvc2l0aW9uIHVuZCBncsO2w59lIMOkbmRlcm4NCiAgICAgICAgIHhheGlzPWxpc3QodGl0bGU9IiIpLCB5YXhpcz1saXN0KHRpdGxlPSJBbnphaGwgQWJnZW9yZG5ldGUiKSkgJT4lDQogIGxheW91dChsZWdlbmQ9bGlzdCh4PTEsIHk9MC41KSkNCmBgYA0KDQojIE1hcCBtaXQgR2VzY2hsZWNodGVydmVydGVpbHVuZyBpbiBkZW4gTGFuZHRhZ2VuDQoNCiogQWxsZSBMYW5kdGFnZSBoZXJhdXNmaWx0ZXJuDQpgYGB7cn0NCnBhcmxhbWVudGFyaWVyX2xhbmR0YWcgPC0gUGFybGFtZW50YXJpZXIgJT4lIA0KICBmaWx0ZXIoS2F0ZWdvcmllICVpbiUgYygiQWJnZW9yZG5ldGVuaGF1cyB2b24gQmVybGluIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICJCYXllcmlzY2hlciBMYW5kdGFnIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICJCcmVtaXNjaGUgQsO8cmdlcnNjaGFmdCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiSGFtYnVyZ2lzY2hlIELDvHJnZXJzY2hhZnQiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIkhlc3Npc2NoZXIgTGFuZHRhZyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiTGFuZHRhZyBCcmFuZGVuYnVyZyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiTGFuZHRhZyBkZXMgU2FhcmxhbmRlcyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiTGFuZHRhZyBNZWNrbGVuYnVyZy1Wb3Jwb21tZXJuIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICJMYW5kdGFnIE5vcmRyaGVpbi1XZXN0ZmFsZW4iLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIkxhbmR0YWcgUmhlaW5sYW5kLVBmYWx6IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICJMYW5kdGFnIFNhY2hzZW4tQW5oYWx0IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICJMYW5kdGFnIHZvbiBCYWRlbi1Xw7xydHRlbWJlcmciLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk5pZWRlcnPDpGNoc2lzY2hlciBMYW5kdGFnIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICJTw6RjaHNpc2NoZXIgTGFuZHRhZyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiU2NobGVzd2lnLUhvbHN0ZWluaXNjaGVyIExhbmR0YWciLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIlRow7xyaW5nZXIgTGFuZHRhZyIpKQ0KYGBgDQoNCiogVmVrdG9yZW4gdW5kIERhdGFmcmFtZSBlcnN0ZWxsZW4gbWl0IGRlbiBLb29yZGluYXRlbiBhbiBkZW5lbiBkaWUgc3DDpHRlcmVuIFBpZS1DaGFydHMgZml4aWVydCB3ZXJkZW4gc29sbGVuLiAoSW1tZXIgZ2VuYXUgaW0gTWl0dGVscHVua3QgZGVzIEJ1bmRlc2xhbmRlcykNCg0KYGBge3J9DQpLYXRlZ29yaWUgPC0gYygiQWJnZW9yZG5ldGVuaGF1cyB2b24gQmVybGluIiwgDQogICAgICAgICAgICAgICAiQmF5ZXJpc2NoZXIgTGFuZHRhZyIsIA0KICAgICAgICAgICAgICAgIkJyZW1pc2NoZSBCw7xyZ2Vyc2NoYWZ0IiwNCiAgICAgICAgICAgICAgICJIYW1idXJnaXNjaGUgQsO8cmdlcnNjaGFmdCIsIA0KICAgICAgICAgICAgICAgIkhlc3Npc2NoZXIgTGFuZHRhZyIsDQogICAgICAgICAgICAgICAiTGFuZHRhZyBCcmFuZGVuYnVyZyIsIA0KICAgICAgICAgICAgICAgIkxhbmR0YWcgZGVzIFNhYXJsYW5kZXMiLA0KICAgICAgICAgICAgICAgIkxhbmR0YWcgTWVja2xlbmJ1cmctVm9ycG9tbWVybiIsDQogICAgICAgICAgICAgICAiTGFuZHRhZyBOb3JkcmhlaW4tV2VzdGZhbGVuIiwNCiAgICAgICAgICAgICAgICJMYW5kdGFnIFJoZWlubGFuZC1QZmFseiIsDQogICAgICAgICAgICAgICAiTGFuZHRhZyBTYWNoc2VuLUFuaGFsdCIsIA0KICAgICAgICAgICAgICAgIkxhbmR0YWcgdm9uIEJhZGVuLVfDvHJ0dGVtYmVyZyIsIA0KICAgICAgICAgICAgICAgIk5pZWRlcnPDpGNoc2lzY2hlciBMYW5kdGFnIiwgDQogICAgICAgICAgICAgICAiU8OkY2hzaXNjaGVyIExhbmR0YWciLCANCiAgICAgICAgICAgICAgICJTY2hsZXN3aWctSG9sc3RlaW5pc2NoZXIgTGFuZHRhZyIsIA0KICAgICAgICAgICAgICAgIlRow7xyaW5nZXIgTGFuZHRhZyIpDQoNCmxhdCA8LSBjKDUyLjUyMDAwOCwNCiAgICAgICAgIDQ4LjkxNzQzMSwNCiAgICAgICAgIDUzLjA3NDk4MiwNCiAgICAgICAgIDUzLjU1MzgxNSwNCiAgICAgICAgIDUwLjY1MjA1MiwNCiAgICAgICAgIDUyLjQwODQxOCwNCiAgICAgICAgIDQ5LjM5NjQyMywNCiAgICAgICAgIDUzLjYxMjY1MSwNCiAgICAgICAgIDUxLjQzMzIzNywNCiAgICAgICAgIDUwLjExODM0NiwNCiAgICAgICAgIDUxLjk1MDI2NSwNCiAgICAgICAgIDQ4LjY2MTYwNCwNCiAgICAgICAgIDUyLjYzNjcwNCwNCiAgICAgICAgIDUxLjEwNDU0MSwNCiAgICAgICAgIDU0LjIxOTM2NywNCiAgICAgICAgIDUxLjAxMDk4OSkNCg0KbG5nIDwtIGMoMTMuNDA0OTU0LA0KICAgICAgICAgMTEuNDA3OTgwLA0KICAgICAgICAgOC44MDcwODAsDQogICAgICAgICA5Ljk5MTU3NSwNCiAgICAgICAgIDkuMTYyNDM4LA0KICAgICAgICAgMTIuNTYyNDkyLA0KICAgICAgICAgNy4wMjI5NjEsDQogICAgICAgICAxMi40Mjk1OTUsDQogICAgICAgICA3LjY2MTU5NCwNCiAgICAgICAgIDcuMzA4OTUzLA0KICAgICAgICAgMTEuNjkyMjc0LA0KICAgICAgICAgOS4zNTAxMzQsDQogICAgICAgICA5Ljg0NTA3NywNCiAgICAgICAgIDEzLjIwMTczOCwNCiAgICAgICAgIDkuNjk2MTE3LA0KICAgICAgICAgMTAuODQ1MzQ2KQ0KDQpidW5kZXNsYWVuZGVyX2tvb3JkaW5hdGVuIDwtIGRhdGEuZnJhbWUoS2F0ZWdvcmllLCBsYXQsIGxuZykNCmBgYA0KDQoqIERhdGFmcmFtZSBuYWNoIEFuemFobCBkZXIgbcOkbm5saWNoZW4gdW5kIHdlaWJsaWNoZW4gUG9saXRpa2VyKmlubmVuIHBybyBCdW5kZXNsYW5kIGZpbHRlcm4uDQoNCmBgYHtyfQ0KcGFybGFtZW50YXJpZXJfbWFuIDwtIHBhcmxhbWVudGFyaWVyX2xhbmR0YWcgJT4lIA0KICBncm91cF9ieShLYXRlZ29yaWUpICU+JSANCiAgZmlsdGVyKEdlc2NobGVjaHQgPT0gIm3DpG5ubGljaCIpICU+JSANCiAgc3VtbWFyaXNlKG3DpG5ubGljaCA9IG4oKSkNCg0KcGFybGFtZW50YXJpZXJfbGFuZHRhZ19nZXNhbXQgPC0gcGFybGFtZW50YXJpZXJfbGFuZHRhZyAlPiUgDQogIGdyb3VwX2J5KEthdGVnb3JpZSkgJT4lIA0KICBmaWx0ZXIoR2VzY2hsZWNodCA9PSAid2VpYmxpY2giKSAlPiUgDQogIHN1bW1hcmlzZSh3ZWlibGljaCA9IG4oKSkgJT4lIA0KICBsZWZ0X2pvaW4ocGFybGFtZW50YXJpZXJfbWFuKQ0KYGBgDQoNCiogS29vcmRpbmF0ZW4gZGVyIHNww6R0ZXJlbiBQaWUtQ2hhcnRzIHp1ciBIYXVwdHRhYmVsbGUgam9pbmVuDQoNCmBgYHtyfQ0KcGFybGFtZW50YXJpZXJfa29vcmRpbmF0ZW4gPC0gcGFybGFtZW50YXJpZXJfbGFuZHRhZ19nZXNhbXQgJT4lIA0KICBsZWZ0X2pvaW4oYnVuZGVzbGFlbmRlcl9rb29yZGluYXRlbiwgYnkgPSBjKCJLYXRlZ29yaWUiID0gIkthdGVnb3JpZSIpKQ0KYGBgDQoNCiMgTWFwIG1pdCBQaWUtQ2hhcnRzDQoNCiogZ2VzY2hsZWNodGVybmV1dHJhbGUgRmFyYmVuIGbDvHIgZGllIEdlc2NobGVjaHRlcnZlcnRlaWx1bmcgZXJzdGVsbGVuLCBzb3dpZSBkaWUgR3JlbnplbiBkZXIgQnVuZGVzbMOkbmRlciBpbXBvcnRpZXJlbiB1bmQgbWl0IE5hbWVuIHZlcnNlaGVuIChwb3B1cCkuDQpgYGB7cn0NCmNvbG9ycyA8LSBjKCIjRkI3RjYyIiwgIiM3NzUyODUiKQ0KDQpncmVuemVuIDwtIHJlYWRSRFMoIkRhdGEvZ2FkbTM2X0RFVV8xX3NwLnJkcyIpICU+JSANCiAgc3RfYXNfc2YoKQ0KDQpwb3B1cF9idW5kZXNsYWVuZGVyIDwtIHBhc3RlMCgiPHN0cm9uZz5CdW5kZXNsYW5kOiA8L3N0cm9uZz4iLCBncmVuemVuJE5BTUVfMSkNCmBgYA0KDQoqIFBpZS1DaGFydHMgbWl0IEhpbGZlIHZvbiBhZGRNaW5pY2hhcnRzIHp1ciBLYXJ0ZSBhbmdlZsO8Z3QuIA0KDQpgYGB7cn0NCm1hcCA8LSBsZWFmbGV0KCkgJT4lIA0KICBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVycyRDYXJ0b0RCLlZveWFnZXJMYWJlbHNVbmRlcikgJT4lIA0KICBzZXRWaWV3KGxuZyA9IDEwLjQ1MTUyNiwgbGF0ID0gNTEuMTY1NjkxLCB6b29tID0gNS41KSAlPiUgDQogIGFkZFBvbHlnb25zKGRhdGEgPSBncmVuemVuLA0KICAgICAgICAgICAgICBmaWxsQ29sb3IgPSAiZ3JleSIsDQogICAgICAgICAgICAgIGZpbGxPcGFjaXR5ID0gMC4xLA0KICAgICAgICAgICAgICB3ZWlnaHQgPSAzLA0KICAgICAgICAgICAgICBjb2xvciA9ICJncmV5IiwNCiAgICAgICAgICAgICAgcG9wdXAgPSBwb3B1cF9idW5kZXNsYWVuZGVyKSAlPiUgDQogIGFkZE1pbmljaGFydHMoDQogICAgcGFybGFtZW50YXJpZXJfa29vcmRpbmF0ZW4kbG5nLCBwYXJsYW1lbnRhcmllcl9rb29yZGluYXRlbiRsYXQsDQogICAgdHlwZSA9ICJwaWUiLA0KICAgIGNoYXJ0ZGF0YSA9IHBhcmxhbWVudGFyaWVyX2tvb3JkaW5hdGVuWywgYygid2VpYmxpY2giLCAibcOkbm5saWNoIildLA0KICAgIGNvbG9yUGFsZXR0ZSA9IGNvbG9ycywNCiAgICB3aWR0aCA9IDQ2LA0KICAgIGhlaWdodCA9IDQ2LA0KICAgIG9wYWNpdHkgPSAwLjgsDQogICAgbGVnZW5kUG9zaXRpb24gPSAiYm90dG9tcmlnaHQiDQogICkNCm1hcA0KYGBgDQoNCiMgVHdlZXRzIGRlciBQb2xpdGlrZXIqaW5uZW4gc2NyYXBlbg0KDQpOaWNodCBhbHMgYXVzZsO8aHJiYXJlbiBDb2RlLCBkYW1pdCBkaWUgRGF0ZW4gbmljaHQgbm9jaG1hbHMgZ2V6b2dlbiB3ZXJkZW4uLi4NCg0KVHdpdHRlcl9hY2NvdW50cyA8LSBQYXJsYW1lbnRhcmllciAlPiUNCiAgZmlsdGVyKEthdGVnb3JpZSE9IkVVLVBhcmxhbWVudCIpICU+JQ0KICBmaWx0ZXIoUGFydGVpIT0iQklXIikgJT4lIA0KICBmaWx0ZXIoUGFydGVpIT0iU1NXIikgJT4lIA0KICBmaWx0ZXIoUGFydGVpIT0iQlZCL0ZXIikgJT4lIA0KICBmaWx0ZXIoUGFydGVpIT0iRlciKSAlPiUgDQogIGZpbHRlcihQYXJ0ZWkhPSJmcmFrdGlvbnNsb3MiKSAlPiUgDQogIGZpbHRlcihTTV9Ud2l0dGVyX3VzZXIgIT0gIiIpDQoNCnRva2VuIDwtIGdldF90b2tlbigpDQp0b2tlbg0KDQphbGxlX3R3ZWV0cyA8LSBsaXN0KCkNCnVzZXJJZExpc3QgPSBsaXN0KFR3aXR0ZXJfYWNjb3VudHMkU01fVHdpdHRlcl91c2VyKQ0KcmwgPC0gcmF0ZV9saW1pdCh0b2tlbiwgInN0YXR1c2VzL3VzZXJfdGltZWxpbmUiKQ0KZm9yKHVzZXIgaW4gdXNlcklkTGlzdFtbMV1dKXsNCiAgYWxsZV90d2VldHNbW3VzZXJdXSA8LSBnZXRfdGltZWxpbmUodXNlciwgbiA9IDIsIGNoZWNrID0gRikNCiAgcHJpbnQoInJhdGUgbGltaXQgcmVtYWluaW5nOiIsIHN0cihybCRyZW1haW5pbmcpKQ0KICBwcmludCgiYXQgdXNlcjoiLCBzdHIodXNlcikpDQogIHJsIDwtIHJsICU+JQ0KICAgIG11dGF0ZShyZW1haW5pbmcgPSByZW1haW5pbmcgLSAxKQ0KICAjIGlmIHJhdGUgbGltaXQgZXhoYXVzdGVkLCB0aGVuIHdhaXQgdG8gcmF0ZSBsaW1pdCByZXNldA0KICBpZiAocmwkcmVtYWluaW5nID09IDVMKSB7DQogICAgcmwgPC0gcmF0ZV9saW1pdCh0b2tlbiwgInN0YXR1c2VzL3VzZXJfdGltZWxpbmUiKQ0KICAgIHByaW50KCJyYXRlIGxpbWl0IGV4Y2VlZGVkLCB3YWl0aW5nIGZvciA5MDBzIGF0IHVzZXIiLCBzdHIodXNlcikpDQogICAgU3lzLnNsZWVwKGFzLm51bWVyaWMocmwkcmVzZXQsICJzZWNzIikpDQogIH0NCn0NCg0KIyMjIE5hY2ggcmVsZXZhbnRlbiBIYXNodGFncyBmaWx0ZXJuIA0KDQoqICJhbGxlX3R3ZWV0cy5yZHMiIGlzdCBkaWUgRGF0ZWkgbWl0IGFsbGVuIGdlem9nZW5lbiBUd2VldHMuDQoqIG5hY2ggcmVsZXZhbnRlbiBUd2VldHMgZmlsdGVybiBtaXQgdm9yaGVyIGJlc3RpbW10ZW4gSGFzaHRhZ3MgKCJUd2l0dGVyLUhhc2h0YWdzLnhsc3giKSwgVHdlZXRzIGluIEtsZWluc2NocmVpYnVuZyBmb3JtYXRpZXJlbiB1bmQgYWxzICJmaW5hbF90d2VldHMucmRzIiBleHBvcnRpZXJlbi4gDQpgYGB7cn0NCmFsbGVfdHdlZXRzIDwtIHJlYWRfcmRzKCJEYXRhL2FsbGVfdHdlZXRzLnJkcyIpDQoNCnN1Y2hiZWdyaWZmZSA8LSByZWFkX2V4Y2VsKCJEYXRhL1R3aXR0ZXItSGFzaHRhZ3MueGxzeCIsIHNoZWV0ID0iVGFiZWxsZTIiKQ0KDQpzdWNoYmVncmlmZmVfdmVjdG9yIDwtIHN1Y2hiZWdyaWZmZSRIYXNodGFncw0KDQphbGxlX3R3ZWV0cyA8LSBiaW5kX3Jvd3MoYWxsZV90d2VldHMpDQoNCmFsbGVfdHdlZXRzIDwtIGFsbGVfdHdlZXRzICU+JSANCiAgbXV0YXRlKHRleHQgPSB0b2xvd2VyKHRleHQpKQ0KDQpmaWx0ZXJ0X3R3ZWV0cyA8LSBhbGxlX3R3ZWV0cyAlPiUgDQogIGZpbHRlcihzdHJfZGV0ZWN0KHRleHQsIHBhc3RlIChzdWNoYmVncmlmZmVfdmVjdG9yLCBjb2xsYXBzZSA9ICJ8IikpKQ0KDQp3cml0ZV9yZHMoZmlsdGVydF90d2VldHMsICJmaW5hbF90d2VldHMucmRzIikNCmBgYA0KDQojIFNlbnRpbWVudGFuYWx5c2UNCg0KKiBuYWNoIGRlbiAiZ3Jvw59lbiIgUGFydGVpZW4gZmlsdGVybg0KKiBhbGxlIFBvbGl0aWtlcippbm5lbiBlbnRmZXJuZW4sIHdlbGNoZSBrZWluZW4gVHdpdHRlcmFjY291bnQgYmVzaXR6ZW4NCiogVXNlcm5hbWVzIGluIEtsZWluc2NocmVpYnVuZyBmb3JtYXRpZXJlbg0KYGBge3J9DQpQYXJsYW1lbnRhcmllcl9zZW50aSA8LSBQYXJsYW1lbnRhcmllciAlPiUgDQogIGZpbHRlcihQYXJ0ZWkhPSJCSVciKSAlPiUgDQogIGZpbHRlcihQYXJ0ZWkhPSJTU1ciKSAlPiUgDQogIGZpbHRlcihQYXJ0ZWkhPSJCVkIvRlciKSAlPiUgDQogIGZpbHRlcihQYXJ0ZWkhPSJGVyIpICU+JSANCiAgZmlsdGVyKFBhcnRlaSE9ImZyYWt0aW9uc2xvcyIpICU+JSANCiAgZmlsdGVyKFNNX1R3aXR0ZXJfdXNlciAhPSAiIikgJT4lIA0KICBzZWxlY3QoTmFtZSwgUGFydGVpLCBTTV9Ud2l0dGVyX3VzZXIsIEdlc2NobGVjaHQpICU+JSANCiAgbXV0YXRlKFNNX1R3aXR0ZXJfdXNlcj10b2xvd2VyKFNNX1R3aXR0ZXJfdXNlcikpDQpgYGANCg0KKiBDRFUgJiBDU1Ugc293aWUgRkRQICYgRFZQIHp1c2FtbWVuZsO8Z2VuIA0KYGBge3J9DQpQYXJsYW1lbnRhcmllcl9zZW50aSRQYXJ0ZWlbUGFybGFtZW50YXJpZXJfc2VudGkkUGFydGVpID09ICJDU1UiXSA8LSAiQ0RVL0NTVSINClBhcmxhbWVudGFyaWVyX3NlbnRpJFBhcnRlaVtQYXJsYW1lbnRhcmllcl9zZW50aSRQYXJ0ZWkgPT0gIkNEVSJdIDwtICJDRFUvQ1NVIg0KUGFybGFtZW50YXJpZXJfc2VudGkkUGFydGVpW1BhcmxhbWVudGFyaWVyX3NlbnRpJFBhcnRlaSA9PSAiRkRQL0RWUCJdIDwtICJGRFAiIA0KYGBgDQoNCiogU2VudGlXUyBpbXBvcnRpZXJlbiwgdW0gcG9zaXRpdmUgdW5kIG5lZ2F0aXZlIFfDtnJ0ZXIgenUga2xhc3NpZml6aWVyZW4NCiogTGlzdGUgenVyIFNlbnRpbWVudGFuYWx5c2UgaXN0IHZvbiBVbml2ZXJzaXTDpHQgTGVpcHppZzogImh0dHBzOi8vd29ydHNjaGF0ei51bmktbGVpcHppZy5kZS9kZS9kb3dubG9hZCINCmBgYHtyfQ0KbG9hZCgiRGF0YS9zZW50aVdTLlJEYXRhIikNCnNlbnRpd3MgPC0gZGljdGlvbmFyeShsaXN0KHBvc2l0aXZlPXBvc2l0aXZlLCBuZWdhdGl2ZT1uZWdhdGl2ZSkpDQpgYGANCg0KKiBDb3JwdXMgYXVzIGRlbiBUZXh0ZW4gZGVyIGdlZmlsdGVydGVuIFR3ZWV0cyBiaWxkZW4NCmBgYHtyfQ0KdHdlZXRfY29ycHVzIDwtIGNvcnB1cyhmaWx0ZXJ0X3R3ZWV0cywgdGV4dF9maWVsZCA9ICJ0ZXh0IikNCmBgYA0KDQoqIHRva2VuaXNpZXJlbiBkZXIgVGV4dGUgdW5kIGJpbGRlbiBlaW5lciBERk0NCiogc2VudGl3cyB1bmQgIlR3ZWV0LVRva2VucyIgenVzYW1tZW5mw7xocmVuLCBzb3dpZSBuYWNoIHNjcmVlbl9uYW1lIGdydXBwaWVyZW4NCg0KYGBge3J9DQp0b2tlbiA8LSB0b2tlbnModHdlZXRfY29ycHVzKQ0KZGZtIDwtIGRmbSh0b2tlbikNCg0Kc2VudGkgPC0gZGZtX2xvb2t1cChkZm0sIHNlbnRpd3MpICANCnNlbnRpIDwtIGRmbV9ncm91cChzZW50aSwgZ3JvdXBzID0gc2NyZWVuX25hbWUpDQpgYGANCg0KKiBERk0genVtIERhdGFmcmFtZSBrb252ZXJ0aWVyZW4NCiogZG9jX2lkIGluIEtsZWluc2NocmVpYnVuZyBmb3JtYXRpZXJlbg0KKiBQYXJsYW1lbnRhcmllcl9zZW50aSBqb2luZW4NCiogR3J1cHBpZXJlbiBuYWNoIFBhcnRlaQ0KKiBTZW50aW1lbnQgZGVyIGVpbnplbG5lbiBVc2VyKmlubmVuIGF1ZiBQYXJ0ZWllYmVuZSB6dXNhbW1lbmZhc3NlbiB1bmQgVmVyaMOkbHRuaXMgcG9zaXRpdmUvbmVnYXRpdmUgYmlsZGVuDQpgYGB7cn0NCnNlbnRpX2ZyYW1lIDwtIHNlbnRpICU+JSANCiAgY29udmVydCh0bz0gImRhdGEuZnJhbWUiKSAlPiUgDQogIGFzX3RpYmJsZSgpICU+JSANCiAgbXV0YXRlKGRvY19pZD10b2xvd2VyKGRvY19pZCkpDQoNCnNlbnRpX2ZpbmFsX2ZyYW1lIDwtIHNlbnRpX2ZyYW1lICU+JSANCiAgZnVsbF9qb2luKFBhcmxhbWVudGFyaWVyX3NlbnRpLCBieT1jKCJkb2NfaWQiPSJTTV9Ud2l0dGVyX3VzZXIiKSkgJT4lIA0KICBncm91cF9ieShQYXJ0ZWkpICU+JSANCiAgc3VtbWFyaXNlKGFjcm9zcyhjKG5lZ2F0aXZlLCBwb3NpdGl2ZSksIH5yb3VuZChzdW0oLiwgbmEucm0gPSBUUlVFKS9zdW0obmVnYXRpdmUgKyBwb3NpdGl2ZSwgbmEucm0gPSBUUlVFICksIGRpZ2l0cyA9IDIpKSkNCmBgYA0KDQojIyMgQmFyY2hhcnQNCg0KKiBQYXJ0ZWkgYWJzdGVpZ2VuZCBuYWNoIG5lZ2F0aXZlbSBTZW50aW1lbnQgc29ydGllcmVuDQoqIEJlc2NocmlmdHVuZyBkZXIgWC0gdW5kIFkgV2VydGUgw6RuZGVybg0KKiBCYXJjaGFydCBiaWxkZW4gdW5kIGluIGdncGxvdGx5IGtvbnZlcnRpZXJlbg0KYGBge3J9DQpzZW50aV9iYXIgPC0gc2VudGlfZmluYWxfZnJhbWUgJT4lIA0KICBtdXRhdGUoUGFydGVpID0gZmN0X3Jlb3JkZXIoUGFydGVpLCBwb3NpdGl2ZSwgbWF4KSkgJT4lIA0KICBwaXZvdF9sb25nZXIoYyhwb3NpdGl2ZSwgbmVnYXRpdmUpLCB2YWx1ZXNfdG8gPSBjKCJWZXJow6RsdG5pcyIpLCBuYW1lc190byA9IGMoIsOEdcOfZXJ1bmciKSkgJT4lIA0KICBnZ3Bsb3QoKSArIA0KICBnZW9tX2JhcihhZXMoUGFydGVpLA0KICAgICAgICAgICAgICAgVmVyaMOkbHRuaXMsICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICBmaWxsID0gw4R1w59lcnVuZyksDQogICAgICAgICAgIHBvc2l0aW9uID0gInN0YWNrIiwNCiAgICAgICAgICAgc3RhdCA9ICJpZGVudGl0eSIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI2Y0NjY2NiIsICIjOEVDOUJCIikpICsgDQogIHRoZW1lX2NsYXNzaWMoKSArIA0KICBsYWJzKA0KICAgIHRpdGxlID0gIsOEdcOfZXJ1bmdlbiBkZXIgUG9saXRpa2VyKmlubmVuIGF1ZiBUd2l0dGVyIHp1bSBUaGVtYSAnR2VuZGVyJyIsDQogICAgc3VidGl0bGUgPSAiRWluc2Now6R0enVuZyBkdXJjaCBTZW50aW1lbnRhbmFseXNlIiwNCiAgICB4ID0gIlBhcnRlaSIsDQogICAgeSA9ICJWZXJow6RsdG5pcyIsDQogICAgZmlsbCA9ICLDhHXDn2VydW5nIg0KICApDQoNCmZpbmFsX3NlbnRpX3Bsb3QgPC0gZ2dwbG90bHkoc2VudGlfYmFyKQ0KZmluYWxfc2VudGlfcGxvdA0KYGBgDQoNCiMgVHdpdHRlciBOZXR6d2VyayANCg0KKiBmaWx0ZXJ0X3R3ZWV0cyAidmVya2xlaW5lcm4iIHVuZCBpbiB0d2VldHNfbmV0d29yayBzcGVpY2hlcm4NCiogc2NyZWVuX25hbWUgaW4gS2xlaW5zY2hyZWlidW5nIGZvcm1hdGllcmVuDQpgYGB7cn0NCnR3ZWV0c19uZXR3b3JrIDwtIGZpbHRlcnRfdHdlZXRzICU+JSANCiAgc2VsZWN0KHNjcmVlbl9uYW1lLA0KICAgICAgICAgcmV0d2VldF9zY3JlZW5fbmFtZSwNCiAgICAgICAgIGNyZWF0ZWRfYXQpICU+JSANCiAgbXV0YXRlKHNjcmVlbl9uYW1lID0gdG9sb3dlcihzY3JlZW5fbmFtZSkpDQpgYGANCg0KKiBQYXJsYW1lbnRhcmllciBEYXRhZnJhbWUgbWl0IHR3ZWV0c19uZXR3b3JrIGpvaW5lbiwgdW0gS2xhcmFtZW4gdW5kIFBhcnRlaXp1Z2Vow7ZyaWdrZWl0IGRlciBQb2xpdGlrZXIqaW5ubmVuIHp1IGJla29tbWVuDQpgYGB7cn0NCnBhcmxhbWVudGFyaWVyX25ldHdvcmsgPC0gUGFybGFtZW50YXJpZXIgJT4lIA0KICBzZWxlY3QoTmFtZSwNCiAgICAgICAgIFBhcnRlaSwNCiAgICAgICAgIFNNX1R3aXR0ZXJfdXNlcikgJT4lIA0KICBkcm9wX25hKFNNX1R3aXR0ZXJfdXNlcikgJT4lIA0KICBtdXRhdGUoU01fVHdpdHRlcl91c2VyID0gdG9sb3dlcihTTV9Ud2l0dGVyX3VzZXIpKSAlPiUgDQogIHJlbmFtZSgic2NyZWVuX25hbWUiID0gIlNNX1R3aXR0ZXJfdXNlciIpDQoNCm5ldHdvcmtfZGF0YSA8LSBwYXJsYW1lbnRhcmllcl9uZXR3b3JrICU+JSANCiAgbGVmdF9qb2luKHR3ZWV0c19uZXR3b3JrLCBieSA9ICJzY3JlZW5fbmFtZSIpDQpgYGANCg0KKiBIw6R1Zmlna2VpdCBkZXIgVHdlZXRzIHp1bSBUaGVtYSBiZXJlY2huZW4gDQoqIEjDpHVmaWdrZWl0IHp1IG5ldHdvcmtfZGF0YSBqb2luZW4NCmBgYHtyfQ0KaGF1ZWZpZ2tlaXRfdHdlZXRzIDwtIG5ldHdvcmtfZGF0YSAlPiUgDQogIGNvdW50KHNjcmVlbl9uYW1lKQ0KDQpuZXR3b3JrX2RhdGEgPC0gbmV0d29ya19kYXRhICU+JSANCiAgbGVmdF9qb2luKGhhdWVmaWdrZWl0X3R3ZWV0cywgYnkgPSAic2NyZWVuX25hbWUiKQ0KYGBgDQoNCiogVmVrdG9yIGRlciBzY3JlZW5fbmFtZXMgYWxsZXIgUG9saXRpa2VyKmlubmVuIGVyc3RlbGxlbg0KKiByZXR3ZWV0X3NjcmVlbl9uYW1lIGF1ZiBkaWVzZSBzY3JlZW5fbmFtZXMgZmlsdGVybiwgdW0gIkZyZW1kdXNlcippbm5lbiIgYXVzenVzY2hsaWXDn2VuIA0KYGBge3J9DQpzY3JlZW5fc3VjaGUgPC0gcGFybGFtZW50YXJpZXJfbmV0d29yayRzY3JlZW5fbmFtZQ0KDQpmaWx0ZXJlZF9yZXR3ZWV0ZXJzIDwtIG5ldHdvcmtfZGF0YSAlPiUgDQogIGZpbHRlcihzdHJfZGV0ZWN0KHJldHdlZXRfc2NyZWVuX25hbWUsIHBhc3RlIChzY3JlZW5fc3VjaGUsIGNvbGxhcHNlID0gInwiKSkpDQpgYGANCg0KKiBOZXR6IG1pdCByZWxldmFudGVuIFdlcnRlbiBkZWZpbmllcmVuIG1pdDogDQoqIEVkZ2VzID0gdm9uIHNjcmVlbl9uYW1lIHp1IHJldHdlZXRfc2NyZWVuX25hbWUNCiogTm9kZXMgPSBQb2xpdGlrZXIqaW5uZW4gKHNjcmVlbl9uYW1lIHVuZCByZXR3ZWV0X3NjcmVlbl9uYW1lKSANCiogSm9pbmUgYXVmcyBOZXR6IFBhcnRlaXp1Z2Vow7ZyaWdrZWl0LCBLbGFybmFtZW4gdW5kIEjDpHVmaWdrZWl0IGRlciBUd2VldHMgenVtIFRoZW1hIChuKQ0KYGBge3J9DQpuZXR6IDwtIGZpbHRlcmVkX3JldHdlZXRlcnMgJT4lIA0KICBmaWx0ZXIoIWlzLm5hKHJldHdlZXRfc2NyZWVuX25hbWUpKSAlPiUgDQogIHNlbGVjdChmcm9tID0gc2NyZWVuX25hbWUsIHRvID0gcmV0d2VldF9zY3JlZW5fbmFtZSkgJT4lIA0KICBhc190YmxfZ3JhcGgNCg0KbmV0eiA8LSBuZXR6ICU+JSANCiAgbXV0YXRlKA0KICAgIGRlZ3JlZSA9IGNlbnRyYWxpdHlfZGVncmVlKG1vZGUgPSAiaW4iKSwgDQogICAgY29tcG9uZW50ID0gZ3JvdXBfY29tcG9uZW50cygpDQogICkgJT4lIA0KICBsZWZ0X2pvaW4obmV0d29ya19kYXRhICU+JSANCiAgICAgICAgICAgICAgc2VsZWN0KE5hbWUsIHNjcmVlbl9uYW1lLCBQYXJ0ZWksIG4pICU+JSBkaXN0aW5jdChzY3JlZW5fbmFtZSwgLmtlZXBfYWxsID0gVCksDQogICAgICAgICAgICBieSA9IGMoICJuYW1lIiA9InNjcmVlbl9uYW1lIikpIA0KYGBgDQoNCiogRmFyYmVuIGbDvHIgUGFydGVpZW4gZGVmaW5pZXJlbg0KYGBge3J9DQpwYXJ0ZWlfZmFyYmVuIDwtIGxpc3QoDQogICJDRFUvQ1NVIiA9ICJibGFjayIsDQogICJTUEQiID0gInJlZCIsDQogICJDU1UiID0gImJsYWNrIiwNCiAgIkZEUCIgPSAiI2UyYjAwNyIsDQogICJHUsOcTkUiID0gIiMwN0MyM0YiLA0KICAiTElOS0UiID0gIiNkZTRjOGEiLCANCiAgIkFmRCIgPSAiYmx1ZSINCikNCmBgYA0KDQojIE5ldHp3ZXJrDQoNClp1d2Vpc3VuZyB2b24gQXR0cmlidXRlbiBhbiBOb2RlczoNCiogUGFydGVpenVnZWjDtnJpZ2tlaXQgaW4gRmFyYmUNCiogS2xhcm5hbWUgZGVyIFBvbGl0aWtlcippbm5lbiBhbHMgTGFiZWwgDQoqIEFuemFobCBkZXIgVHdlZXRzIGluIEdyw7bDn2UNCmBgYHtyfQ0KbmV0el9wbG90IDwtIG5ldHogJT4lIA0KICBmaWx0ZXIoY29tcG9uZW50IDw9IDYpICU+JSANCiAgbXV0YXRlKGRlZ3JlZSA9IGNlbnRyYWxpdHlfZGVncmVlKG1vZGUgPSAiaW4iKSkgJT4lIA0KICBnZ3JhcGgobGF5b3V0ID0gImZyIikgKw0KICBnZW9tX2VkZ2VfbGluayhhbHBoYSA9IDAuMjUsIGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgiNSIsICJtbSIpKSkgKw0KICBnZW9tX25vZGVfcG9pbnQoYWVzKHNpemUgPSBuLCBjb2xvciA9IFBhcnRlaSkpICsgDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYXJ0ZWlfZmFyYmVuKSArDQogIHRoZW1lX2dyYXBoKGJhY2tncm91bmQgPSAid2hpdGUiKSArICMgdGhlbWUNCiAgZ2VvbV9ub2RlX2xhYmVsKGFlcyhmaWx0ZXIgPSBuID49IDE1LCBsYWJlbCA9IE5hbWUpLCByZXBlbCA9IFQsIHNob3cubGVnZW5kID0gRiwgYWxwaGEgPSAwLjUpICsgI3Bvc2l0aW9uID0gImppdHRlciINCiAgbGFicyh0aXRsZSA9ICJSZXR3ZWV0LU5ldHp3ZXJrZSBkZXV0c2NoZXIgUG9saXRpa2VyKmlubmVuIiwgc2l6ZSA9ICJBbnphaGwgVHdlZXRzIiwgc3VidGl0bGUgPSAienVtIFRoZW1hICdHZW5kZXInIGFiIDIwMTYiKQ0KYGBgDQpgYGB7cn0NCm5ldHpfcGxvdCANCmBgYA0KDQpOT0RFUyBERVVUTElDSEVSRSBBQlNUVUZVTkcsIFZMVC4gVEhFTUUgRlVOS1RJT05JRVJUIE5JQ0hUIFJJQ0hUSUcNCg==